package cevent.source.cloudcenter.gateway.filter;/**
 * Created by Cevent on 2021/5/20.
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * @author cevent
 * @description 服务过滤器实现
 * EmployeeLogin为过滤器约定name，在properties中配置过滤器filters，name=EmployeeLogin
 * @date 2021/5/20 8:49
 */
@Component
public class EmployeeLoginGatewayFilter implements GatewayFilter, Ordered {
    private static final String BUSINESS_NAME="路由转发gateway";
    private static final Logger LOG= LoggerFactory.getLogger(EmployeeLoginGatewayFilter.class);

    @Resource
    private RedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //1.获取请求uri
        String path=exchange.getRequest().getURI().getPath();
        //2.请求路径不包含admin，非后台请求，不拦截
        if(!path.contains("/admin/")){
            return chain.filter(exchange);
        }
        //3.登录/登出/验证码不拦截
        if(path.contains("/admin/employee/login")
                || path.contains("/admin/employee/loginout")
                || path.contains("/admin/kaptcha")){
            LOG.info("不需要控台登录验证：{}",path);
            return chain.filter(exchange);
        }
        //4.获取请求header存入的参数
        String token=exchange.getRequest().getHeaders().getFirst("token");
        LOG.info("gateway filter登录拦截，获取token：{}",token);
        if(token==null || token.isEmpty()){
            LOG.info("token不存在，请求被拦截，返回响应un authorized未授权-->401");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        // TODO 这里如果取消redis，使用requst的session
        Object obj=redisTemplate.opsForValue().get(token);
        if(obj==null){
            LOG.warn("token无效,已超时，请求被拦截");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }else{
            LOG.info("已登录，token-->obj：{}",obj);
            //增加前端接口权限拦截
            LOG.info("登录用户接口权限校验：{}",path);
            boolean existAuthority=false;
            //gateway没有引用server，没有empLoginDto，这里使用JSON操作
            JSONObject empLoginDto= JSON.parseObject(String.valueOf(obj));
            //校验通过，刷新token时间
            redisTemplate.opsForValue().set(token, JSON.toJSONString(empLoginDto),3600, TimeUnit.SECONDS);
            //获取允许的请求接口
            JSONArray requests=empLoginDto.getJSONArray("requests");
            LOG.info("用户的全部接口：{}",requests);
            LOG.info("进入接口拦截！");
            for(int i=0;i<requests.size();i++){
                String req=(String) requests.get(i);
                //这里可以是contains、equals，凡路径包含请求内容，则通过
                if(path.contains(req)){
                    LOG.info("通过校验的接口：{}",req);
                    existAuthority=true;
                    break;
                }
                //通过校验
            }
            if(existAuthority){
                LOG.info("用户访问接口权限校验通过！");
                return chain.filter(exchange);
            }else{
                LOG.warn("用户没有权限");
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }

        }

    }

    @Override
    public int getOrder() {
        return 1;
    }
}
